#pragma once

#include <sw/redis++/redis.h>
#include <string>
#include <chrono>
#include "logger.hpp"

namespace suye
{
class RateLimiter
{
public:
    using ptr = std::shared_ptr<RateLimiter>;

    RateLimiter(const std::shared_ptr<sw::redis::Redis>& redis_client)
        : _redis_client(redis_client) {}

    // 令牌桶算法限流
    // key: 限流键（如：rate_limit:login:192.168.1.1）
    // max_requests: 时间窗口内最大请求数
    // window_seconds: 时间窗口（秒）
    bool allowRequest(const std::string& key,
                      int max_requests,
                      int window_seconds) 
    {
        try {
            // 使用Redis的INCR和EXPIRE实现简单限流
            std::string full_key = "rate_limit:" + key;
            
            auto count = _redis_client->incr(full_key);

            // 第一次请求，设置过期时间
            if (count == 1) {
                _redis_client->expire(full_key, window_seconds);
            }

            if (count > max_requests) {
                LOG_WARN("限流触发: {} 超过 {}/{}", key, count, max_requests);
                return false;
            }

            LOG_DEBUG("限流检查通过: {} {}/{}", key, count, max_requests);
            return true;

        } catch (const std::exception& e) {
            LOG_ERROR("限流检查失败: {}", e.what());
            // 降级策略：Redis失败时放行（或根据业务选择拒绝）
            return true;
        }
    }

    // 滑动窗口限流（更精确）
    bool allowRequestSlidingWindow(const std::string& key,
                                  int max_requests,
                                  int window_seconds)
    {
        try {
            std::string full_key = "rate_limit:sw:" + key;
            auto now = std::chrono::system_clock::now();
            auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();

            // 使用Redis Sorted Set实现滑动窗口
            // 1. 移除窗口外的记录
            auto min_time =  timestamp - (window_seconds * 1000);
            _redis_client->zremrangebyscore(full_key, sw::redis::LeftBoundedInterval<double>((double)min_time, sw::redis::BoundType::RIGHT_OPEN));

            // 2. 统计当前窗口内的请求数
            auto count = _redis_client->zcard(full_key);

            if (count >= max_requests) {
                LOG_WARN("限流触发: {} 超过 {}/{}", key, count, max_requests);
                return false;
            }

            // 3. 添加当前请求到窗口
            _redis_client->zadd(full_key, std::to_string(timestamp), (double)timestamp);

            // 4. 设置过期时间
            _redis_client->expire(full_key, std::chrono::seconds(window_seconds + 1));
            
            LOG_DEBUG("限流检查通过: {} {}/{}", key, count, max_requests);
            return true;

        } catch (const std::exception& e) {
            LOG_ERROR("滑动窗口限流检查失败: {}", e.what());
            return true;
        }
    }

private:
    std::shared_ptr<sw::redis::Redis> _redis_client;
};
}